using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Drawing.Printing;
using Skywave.Windows.Forms.RuntimeDesign;
using System.Drawing;

namespace Skywave.Drawing.Printing
{
    public partial class AdvancedPrintDocument : Component
    {
        public AdvancedPrintDocument()
        {
            InitializeComponent();
            mHeader.SetFieldValue += new FormDesignerSetFieldValueEventHandler(mHeader_SetFieldValue);
            mFooter.SetFieldValue += new FormDesignerSetFieldValueEventHandler(mFooter_SetFieldValue);
        }

        public AdvancedPrintDocument(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            mHeader.SetFieldValue += new FormDesignerSetFieldValueEventHandler(mHeader_SetFieldValue);
            mFooter.SetFieldValue += new FormDesignerSetFieldValueEventHandler(mFooter_SetFieldValue);
        }
        public event PrintEventHandler BeginPrint;
        public event PrintPageEventHandler PrintPage;
        public event PrintPageEventHandler PrintEntirePage;
        public event FormDesignerSetFieldValueEventHandler HeaderSetFieldValue;
        public event FormDesignerSetFieldValueEventHandler FooterSetFieldValue;
        const int InitialHeaderFooterHeight = 50;

        private void InitializeHeaderFooter()
        {
            mHeader.InitializeMe();
            mFooter.InitializeMe();
        }

        private ContentAlignment mHeaderPosition = ContentAlignment.TopCenter;
        [DefaultValue(ContentAlignment.TopCenter)]
        public ContentAlignment HeaderPosition
        {
            get { return mHeaderPosition; }
            set { mHeaderPosition = value; }
        }

        private ContentAlignment mFooterPosition = ContentAlignment.TopCenter;
        [DefaultValue(ContentAlignment.TopCenter)]
        public ContentAlignment FooterPosition
        {
            get { return mFooterPosition; }
            set { mFooterPosition = value; }
        }

        private bool mPrintHeader;
        [DefaultValue(true)]
        public bool PrintHeader
        {
            get { return mPrintHeader; }
            set { mPrintHeader = value; }
        }

        private bool mPrintFooter;
        [DefaultValue(true)]
        public bool PrintFooter
        {
            get { return mPrintFooter; }
            set { mPrintFooter = value; }
        }

        private bool mTileVertically;
        [DefaultValue(false)]
        public bool TileVertically
        {
            get { return mTileVertically; }
            set { mTileVertically = value; }
        }

        private bool mTileHorizontally;
        [DefaultValue(false)]
        public bool TileHorizontally
        {
            get { return mTileHorizontally; }
            set { mTileHorizontally = value; }
        }

        private int mPrintAreaWidth = 0;
        [DefaultValue(0)]
        public int PrintAreaWidth
        {
            get { return mPrintAreaWidth; }
            set { mPrintAreaWidth = value; }
        }

        private int mPrintAreaHeight = 0;
        [DefaultValue(0)]
        public int PrintAreaHeight
        {
            get { return mPrintAreaHeight; }
            set { mPrintAreaHeight = value; }
        }

        private int mBetweenBorderSize = 10;
        [DefaultValue(10)]
        public int BetweenBorderSize
        {
            get { return mBetweenBorderSize; }
            set { mBetweenBorderSize = value; }
        }

        private FormDesigner mHeader = new FormDesigner();
        [Browsable(false)]
        public FormDesigner Header
        {
            get
            {
                if (this.DesignMode)
                    return null;
                else
                {
                    if (mHeader == null)
                        InitializeHeaderFooter();
                    return mHeader;
                }
            }
            set
            {
                if (mHeader == null) InitializeHeaderFooter();
                if (mHeader == value || value == null) return;
                //if (mHeader == null) mHeader = new FormDesigner();
                mHeader.CopyFrom(value);
                mHeader.ChoosedPrintDocument = mDocument;
            }
        }
        private FormDesigner mFooter = new FormDesigner();
        [Browsable(false)]
        public FormDesigner Footer
        {
            get
            {
                if (this.DesignMode)
                    return null;
                else
                {
                    if (mHeader == null)
                        InitializeHeaderFooter();
                    return mFooter;
                }
            }
            set
            {
                if (mHeader == null) InitializeHeaderFooter();
                if (mFooter == value || value == null) return;
                //if (mFooter == null) mFooter = new FormDesigner();
                mFooter.CopyFrom(value);
                mFooter.ChoosedPrintDocument = mDocument;
            }
        }
        private PrintDocument mDocument;
        public PrintDocument Document
        {
            get { return mDocument; }
            set
            {
                if (mDocument == value || value == null) return;
                mDocument = value;
                mDocument.BeginPrint += new PrintEventHandler(mDocument_BeginPrint);
                mDocument.PrintPage += new PrintPageEventHandler(mDocument_PrintPage);
                if (mHeader != null)
                    mHeader.ChoosedPrintDocument = mDocument;
                if (mFooter != null)
                    mFooter.ChoosedPrintDocument = mDocument;
            }
        }

        int printCountVertically, printCountHorizontally;
        private void mDocument_BeginPrint(object sender, PrintEventArgs e)
        {
            printCountHorizontally = 0; printCountVertically = 0;
            if (BeginPrint != null)
            {
                BeginPrint(sender, e);
            }
        }

        private void mDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            int headerCredit, footerCredit;
            if (mPrintHeader)
            {
                headerCredit = 1;
            }
            else
            {
                headerCredit = 0;
            }
            if (mPrintFooter)
            {
                footerCredit = 1;
            }
            else
            {
                footerCredit = 0;
            }
            if (PrintEntirePage != null)
                PrintEntirePage(sender, new PrintPageEventArgs(e.Graphics, new Rectangle(e.MarginBounds.Left, e.MarginBounds.Top + headerCredit * Header.PalleteSize.Height, e.MarginBounds.Width, e.MarginBounds.Height - headerCredit * Header.PalleteSize.Height - footerCredit * Footer.PalleteSize.Height), e.PageBounds, e.PageSettings));

        StartPrint:
            int x = e.MarginBounds.X;
            int y = e.MarginBounds.Y;
            int w = mPrintAreaWidth;
            int h = mPrintAreaHeight;
            int int1;
            bool gotoNewPage;

            gotoNewPage = true;
            if (mTileHorizontally)
            {
                gotoNewPage = false;
                int1 = headerCredit * Header.PalleteSize.Height + mPrintAreaHeight + footerCredit * Footer.PalleteSize.Height;
                if (int1 > e.MarginBounds.Height)
                {
                    mPrintAreaHeight = e.MarginBounds.Height - headerCredit * Header.PalleteSize.Height - footerCredit * Footer.PalleteSize.Height;
                    int1 = e.MarginBounds.Height - 1;
                }
                if (e.MarginBounds.Width >= printCountHorizontally * (mPrintAreaWidth + mBetweenBorderSize) + mPrintAreaWidth)
                {
                    x += printCountHorizontally * (mPrintAreaWidth + mBetweenBorderSize);
                    y += printCountVertically * (int1 + mBetweenBorderSize);
                    printCountHorizontally += 1;
                }
                else if (mTileVertically)
                {
                    if (printCountHorizontally > 0) printCountVertically += 1;
                    printCountHorizontally = 1;
                    if (e.MarginBounds.Height >= (printCountVertically) * (int1 + mBetweenBorderSize) + (int1))
                    {
                        y += (printCountVertically) * (int1 + mBetweenBorderSize);
                        if (printCountVertically == 0) printCountVertically = 1;
                    }
                    else
                    {
                        gotoNewPage = true;
                    }
                }
                else
                {
                    gotoNewPage = true;
                }
            }
            else if (mTileVertically)
            {
                gotoNewPage = false;
                int1 = headerCredit * Header.PalleteSize.Height + mPrintAreaHeight + footerCredit * Footer.PalleteSize.Height;
                if (e.MarginBounds.Height >= printCountVertically * (int1 + mBetweenBorderSize) + (int1))
                {
                    y += printCountVertically * (int1 + mBetweenBorderSize);
                    printCountVertically += 1;
                }
                else
                {
                    gotoNewPage = true;
                }
            }
            y += headerCredit * Header.PalleteSize.Height;


            if (mTileHorizontally || mTileVertically)
            {
                if (gotoNewPage)
                {
                    printCountHorizontally = 0;
                    printCountVertically = 0;
                    e.HasMorePages = true;
                }
                else
                {
                    PrintPageEventArgs newE = new PrintPageEventArgs(e.Graphics, new Rectangle(x, y, w, h), e.PageBounds, e.PageSettings);
                    if (PrintPage != null)
                        PrintPage(this, newE);
                    if (mPrintHeader)
                    {
                        y -= Header.PalleteSize.Height;
                        PrintHeaderFooter(e.Graphics, Header, new Rectangle(x, y, w, Header.PalleteSize.Height), mHeaderPosition);
                        //Header.PrintOn(e.Graphics, new Rectangle(x, y, w, Header.PalleteSize.Height));
                    }
                    if (mPrintFooter)
                    {
                        y += Header.PalleteSize.Height + mPrintAreaHeight;
                        PrintHeaderFooter(e.Graphics, Footer, new Rectangle(x, y, w, Footer.PalleteSize.Height), mFooterPosition);
                        //Footer.PrintOn(e.Graphics, new Rectangle(x, y, w, Footer.PalleteSize.Height));
                    }
                    if (newE.Cancel)
                    {
                        e.Cancel = true;
                    }
                    else
                    {
                        if (newE.HasMorePages) goto StartPrint; else e.HasMorePages = false;
                    }
                }
            }
            else
            {
                w = e.MarginBounds.Width;
                h = e.MarginBounds.Height - headerCredit * Header.PalleteSize.Height - footerCredit * Footer.PalleteSize.Height;
                PrintPageEventArgs newE = new PrintPageEventArgs(e.Graphics, new Rectangle(x, y, w, h), e.PageBounds, e.PageSettings);
                if (PrintPage != null)
                    PrintPage(this, newE);
                if (mPrintHeader)
                {
                    y -= Header.PalleteSize.Height;
                    PrintHeaderFooter(e.Graphics, Header, new Rectangle(x, y, w, Header.PalleteSize.Height), mHeaderPosition);
                    //Header.PrintOn(e.Graphics, new Rectangle(x, y, w, Header.PalleteSize.Height));
                }
                if (mPrintFooter)
                {
                    y = e.MarginBounds.Bottom - Footer.PalleteSize.Height;
                    PrintHeaderFooter(e.Graphics, Footer, new Rectangle(x, y, w, Footer.PalleteSize.Height), mFooterPosition);
                    //Footer.PrintOn(e.Graphics, new Rectangle(x, y, w, Footer.PalleteSize.Height));
                }
                e.HasMorePages = newE.HasMorePages;
                e.Cancel = newE.Cancel;
            }
        }

        private void PrintHeaderFooter(Graphics g, FormDesigner HF, Rectangle pBounds, ContentAlignment hfP)
        {
            int newX = pBounds.X;
            if (hfP == ContentAlignment.TopCenter)
            {
                if (HF.PalleteSize.Width < pBounds.Width)
                {
                    newX = pBounds.X + ((pBounds.Width - HF.PalleteSize.Width) / 2);
                }
            }
            else if (hfP == ContentAlignment.TopRight)
            {
                newX = pBounds.X + (pBounds.Width - HF.PalleteSize.Width);
            }
            pBounds = new Rectangle(newX, pBounds.Y, pBounds.Width, pBounds.Height);
            HF.PrintOn(g, pBounds);
        }

        private void mHeader_SetFieldValue(object sender, FormDesignerSetFieldValueEventArgs e)
        {
            if (HeaderSetFieldValue != null) HeaderSetFieldValue(this, e);
        }

        private void mFooter_SetFieldValue(object sender, FormDesignerSetFieldValueEventArgs e)
        {
            if (FooterSetFieldValue != null) FooterSetFieldValue(this, e);
        }
    }
}
